package com.alibaba.citrus.cr.platform.enhance.facade.service.role;

import com.alibaba.citrus.cr.common.exception.FacadeException;
import com.alibaba.citrus.cr.platform.enhance.dto.PermissionTreePortalResp;
import com.alibaba.citrus.cr.platform.enhance.repository.RoleRepository;
import com.alibaba.cz.base.model.enterprise.constant.RoleTypeEnum;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.model.dto.BaselineGetEmployeeByIdsAllRequest;
import com.epoch.app.bcorder.model.dto.BaselineGetEmployeeOrganizationsRequest;
import com.epoch.app.bcorder.model.dto.BaselineGetEmployeeRolesById2Request;
import com.epoch.app.bcorder.model.dto.BaselineGetEmployeesByRole2Request;
import com.epoch.app.bcorder.model.dto.BaselineGetGroupMenusRequest;
import com.epoch.app.bcorder.model.dto.BaselineGetOrganiztionsByPage2Request;
import com.epoch.app.bcorder.model.dto.EmployeeGetCurrentLoginResponse;
import com.epoch.app.bcorder.model.dto.EmployeeSDO;
import com.epoch.app.bcorder.model.dto.MenuSDO;
import com.epoch.app.bcorder.model.dto.OrganizationSDO;
import com.epoch.app.bcorder.model.dto.PermissionGroupTree;
import com.epoch.app.bcorder.model.dto.PermissionSDO;
import com.epoch.app.bcorder.model.dto.RolePermissionSDO;
import com.epoch.app.bcorder.model.dto.RoleSDO;
import com.epoch.app.bcorder.service.BaseDataService;
import com.epoch.app.bcorder.service.BcOrderService;
import com.epoch.app.crplatformenhance.contants.CrPlatformEnhanceConstants;
import com.epoch.app.crplatformenhance.enums.RoleQueryTypeEnum;
import com.epoch.app.crplatformenhance.model.dto.QueryRoleRequest;
import com.epoch.app.crplatformenhance.rolequery.dto.GetRoleInfoToPageRequest;
import com.epoch.app.crplatformenhance.rolequery.dto.GetRoleListToPageRequest;
import com.epoch.app.crplatformenhance.rolequery.dto.PageQueryEmployeesByRoleRequest;
import com.epoch.app.crplatformenhance.rolequery.service.RoleQueryService;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhoubc
 * @description: TODO
 * @date 2022/11/30 17:15
 */
@Component
@Primary
public class RoleQueryServiceImpl implements RoleQueryService {
    private static Log log = Log.getLogger(RoleQueryServiceImpl.class);

    private final String PORTAL_MENU_ROOT_PARENT_ID = "0";

    public final static String ADMIN_ROLE_ID = "1";

    public final static Integer COMMON_ROLE_GROUP = 1;

    @Resource
    private BcOrderService bcOrderService;

    @Resource
    private BaseDataService baseDataService;

    @Resource
    private RoleRepository roleRepository;

    @Override
    public Result<List<RoleSDO>> getRoleListToPage(GetRoleListToPageRequest getRoleListToPageRequest) {
        QueryRoleRequest queryRoleRequest = new QueryRoleRequest();
        queryRoleRequest.setId(getRoleListToPageRequest.getId());
        queryRoleRequest.setName(getRoleListToPageRequest.getName());
        queryRoleRequest.setCode(getRoleListToPageRequest.getCode());
        queryRoleRequest.setType(getRoleListToPageRequest.getPermissionType());
        queryRoleRequest.setNeedPermission(false);
        String type = getRoleListToPageRequest.getType();
        //获取用户信息
        EmployeeGetCurrentLoginResponse loginUser = bcOrderService.employeeGetCurrentLogin();

        BaselineGetEmployeeRolesById2Request getEmployeeRolesByIdRequest = new BaselineGetEmployeeRolesById2Request();
        getEmployeeRolesByIdRequest.setBelongOrganizationId(RoleQueryTypeEnum.OTS.getBelongOrganizationId());
        getEmployeeRolesByIdRequest.setEmployeeId(loginUser.getEmployeeId());
        Result<List<RoleSDO>> rolesResult = baseDataService.baselineGetEmployeeRolesById2(getEmployeeRolesByIdRequest);
        List<RoleSDO> userRoles = new ArrayList<>();
        if(rolesResult!=null && CollectionUtils.isNotEmpty(rolesResult.getResult())){
            userRoles = rolesResult.getResult();
        }
        //页面只展示1、5、6的belongOrgId的角色
        List<String> showRoleListBelongOrgId = Lists.newArrayList(RoleQueryTypeEnum.OTS.getBelongOrganizationId(),RoleQueryTypeEnum.CTS.getBelongOrganizationId(),RoleQueryTypeEnum.OMNI.getBelongOrganizationId());
        //先筛选用户所拥有 1、5、6的belongOrgId的功能角色列表
        userRoles = userRoles.stream()
                .filter(x-> RoleTypeEnum.FUNCTION.getNo().equals(x.getType()))
                .filter(x->showRoleListBelongOrgId.contains(x.getBelongOrganizationId())).collect(Collectors.toList());

        //请求端,支持type不传,自动选择,员工管理页面不传的~
        if(StringUtils.isBlank(type)){
            List<String> queryBelongOrganizationIds = null;
            if(CollectionUtils.isNotEmpty(userRoles)){
                List<RoleSDO> admain = userRoles.stream().filter(x->ADMIN_ROLE_ID.equals(x.getId())).collect(Collectors.toList());
                //用户是平台超级管理员，展示所有角色
                if(CollectionUtils.isNotEmpty(admain)){
                    queryBelongOrganizationIds = showRoleListBelongOrgId;
                //其他情况则按登录用户角色的belongOrgId，只展示同类型的角色，
                }else{
                    Set<String> belongOrganizationIdSet = userRoles.stream().map(RoleSDO::getBelongOrganizationId).collect(Collectors.toSet());
                    queryBelongOrganizationIds = Lists.newArrayList(belongOrganizationIdSet);
                }
                queryRoleRequest.setBelongOrganizationIds(queryBelongOrganizationIds);
            //啥也不是，返回[]
            }else{
                return Result.listSuccess(new ArrayList<>(),0);
            }
        }else{
            //订单PC端查询角色列表type默认为“platform”,对应查询角色的belongOrganizationId参数为登录用户的belongOrganizationId，其他端特判处理传值
            RoleQueryTypeEnum roleQueryTypeEnum = RoleQueryTypeEnum.of(type);
//            if(roleQueryTypeEnum == null){
//                throw new FacadeException(ErrorMessage.code("OTS-01-001-02-15-004"));
//            }
            queryRoleRequest.setBelongOrganizationId(roleQueryTypeEnum!=null?roleQueryTypeEnum.getBelongOrganizationId():loginUser.getBelongOrganizationId());
        }
        List<RoleSDO> list = roleRepository.queryRoleList(queryRoleRequest);

        //如果当前用户只要拥有通用角色，就展示所有角色
        Set<Integer> userRolesGroup = userRoles.stream().map(x->x.getGroup()).collect(Collectors.toSet());
        List<Integer> commonGroup = userRolesGroup.stream().filter(x->COMMON_ROLE_GROUP.equals(x)).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(commonGroup)){
            list = Nullable.stream(list).filter(x->userRolesGroup.contains(x.getGroup())).collect(Collectors.toList());
        }

        //配置项指定超级平台管理员，才显示平台管理员角色
        String adminConfig = StringUtils.isNotBlank(CrPlatformEnhanceConstants.ADMIN_EMPLOYEE_ID())?CrPlatformEnhanceConstants.ADMIN_EMPLOYEE_ID():"";
        List<String> adminList = Arrays.asList(adminConfig.split(";"));
        if(!adminList.contains(loginUser.getEmployeeId())){
            list = Nullable.stream(list).filter(x->!ADMIN_ROLE_ID.equals(x.getId())).collect(Collectors.toList());
        }
        enichRoleSDO(list);
        return Result.listSuccess(list,list.size());
    }

    @Override
    public Result<RoleSDO> getRoleInfoToPage(GetRoleInfoToPageRequest getRoleInfoToPageRequest) {
        if(StringUtils.isBlank(getRoleInfoToPageRequest.getId())&&StringUtils.isBlank(getRoleInfoToPageRequest.getCode())){
           return Result.success(new RoleSDO());
        }
        QueryRoleRequest queryRoleRequest = new QueryRoleRequest();
        queryRoleRequest.setId(getRoleInfoToPageRequest.getId());
        queryRoleRequest.setCode(getRoleInfoToPageRequest.getCode());
        if(StringUtils.isNotBlank(getRoleInfoToPageRequest.getType())){
            RoleQueryTypeEnum roleQueryTypeEnum = RoleQueryTypeEnum.of(getRoleInfoToPageRequest.getType());
            if(roleQueryTypeEnum == null){
                throw new FacadeException(ErrorMessage.code("OTS-01-001-02-15-004"));
            }
            queryRoleRequest.setBelongOrganizationId(roleQueryTypeEnum.getBelongOrganizationId());
        }else{
            EmployeeGetCurrentLoginResponse loginUser = bcOrderService.employeeGetCurrentLogin();
            queryRoleRequest.setBelongOrganizationId(loginUser.getBelongOrganizationId());
        }
        RolePermissionSDO sdo = roleRepository.queryRoleInfo(queryRoleRequest);
        if(sdo == null){
            return Result.fail("OTS-01-001-02-15-001",ErrorMessage.code("OTS-01-001-02-15-001").getDisplayErrorMessage());
        }
        //该角色已拥有的权限菜单
        List<PermissionSDO> permissionList = Nullable.stream(sdo.getPermissions()).map(x->x.getPermissionSDO()).collect(Collectors.toList());
        Map<String,PermissionSDO> permissionMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(permissionList)){
            permissionList.forEach(permission -> {
                permission.setPermissionId(permission.getId());
                permission.setHaving(true);
            });
            permissionMap = permissionList.stream().collect(Collectors.toMap(PermissionSDO::getId,Function.identity(),(v1,v2)->v1));
        }
        //查询所有菜单组权限树
        List<PermissionGroupTree> permissionGroupRespList = listPermission(Arrays.stream(RoleQueryTypeEnum.values()).map(x->x.getCode()).collect(Collectors.toList()),permissionMap);
        //组装数据
        enichRoleSDO(Lists.newArrayList(sdo.getRoleSDO()));
        RoleSDO resp = new RoleSDO();
        BeanUtils.copyProperties(sdo.getRoleSDO(),resp);
        resp.setPermissionList(permissionList);
        resp.setPermissionTreeList(permissionGroupRespList);
        return Result.success(resp);
    }

    @Override
    public Result<List<EmployeeSDO>> pageQueryEmployeesByRole(PageQueryEmployeesByRoleRequest pageQueryEmployeesByRoleRequest) {
        BaselineGetEmployeesByRole2Request getEmployeesByRoleRequest = new BaselineGetEmployeesByRole2Request();
        if(StringUtils.isNotBlank(pageQueryEmployeesByRoleRequest.getSearchValue())){
            Boolean b = enichQueryParam(pageQueryEmployeesByRoleRequest,getEmployeesByRoleRequest);
            if(!b){
                return Result.listSuccess(new ArrayList<>(),0);
            }
        }
        getEmployeesByRoleRequest.setRoleId(pageQueryEmployeesByRoleRequest.getRoleId());
        getEmployeesByRoleRequest.setStart(pageQueryEmployeesByRoleRequest.getStart());
        getEmployeesByRoleRequest.setLimit(pageQueryEmployeesByRoleRequest.getLimit());
        Result<List<EmployeeSDO>> emplyeeResult = baseDataService.baselineGetEmployeesByRole2(getEmployeesByRoleRequest);
        if(!emplyeeResult.isSuccess()){
            return Result.fail(emplyeeResult.getErrorCode(),emplyeeResult.getMessage());
        }
        if(CollectionUtils.isEmpty(emplyeeResult.getResult())){
            return Result.listSuccess(new ArrayList<>(),0);
        }

        for (EmployeeSDO sdo : emplyeeResult.getResult()) {
            try {
                //查询员工角色
                BaselineGetEmployeeRolesById2Request getEmployeeRolesByIdRequest = new BaselineGetEmployeeRolesById2Request();
                getEmployeeRolesByIdRequest.setEmployeeId(sdo.getId());
                Result<List<RoleSDO>> roleResult = baseDataService.baselineGetEmployeeRolesById2(getEmployeeRolesByIdRequest);
                if(roleResult != null && CollectionUtils.isNotEmpty(roleResult.getResult())){
                    sdo.setRoleList(roleResult.getResult());
                }
                //查询员工组织
                BaselineGetEmployeeOrganizationsRequest getEmployeeOrganizationsRequest = new BaselineGetEmployeeOrganizationsRequest();
                getEmployeeOrganizationsRequest.setEmployeeId(sdo.getId());
                Result<List<OrganizationSDO>> organizationResult = baseDataService.baselineGetEmployeeOrganizations(getEmployeeOrganizationsRequest);
                if(organizationResult != null && CollectionUtils.isNotEmpty(organizationResult.getResult())){
                    sdo.setOrganizationList(organizationResult.getResult());
                }
            } catch (Exception e) {
                log.error("roleQueryServiceImpl_pageQueryEmployeesByRole_get_role_and_organization_error,employee={}", JSONObject.toJSONString(sdo));
                log.error("roleQueryServiceImpl_pageQueryEmployeesByRole_get_role_and_organization_error ",e);
            }
        }
        return Result.listSuccess(emplyeeResult.getResult(),emplyeeResult.getTotal());
    }

    private Boolean enichQueryParam(PageQueryEmployeesByRoleRequest pageQueryEmployeesByRoleRequest,BaselineGetEmployeesByRole2Request getEmployeesByRoleRequest){
        String searchType = pageQueryEmployeesByRoleRequest.getSearchType();
        String searchValue = pageQueryEmployeesByRoleRequest.getSearchValue();
        if(searchType != null){
            switch (searchType) {
                case "email":
                    getEmployeesByRoleRequest.setEmail(searchValue);
                    break;
                case "name":
                    getEmployeesByRoleRequest.setName(searchValue);
                    break;
                case "nick":
                    getEmployeesByRoleRequest.setNick(searchValue);
                    break;
                case "phone":
                    getEmployeesByRoleRequest.setPhone(searchValue);
                    break;
                case "workId":
                    getEmployeesByRoleRequest.setWorkId(searchValue);
                    break;
                case "sourceType":
                    getEmployeesByRoleRequest.setSourceType(new Integer(searchValue));
                    break;
                case "organizationName":
                    BaselineGetOrganiztionsByPage2Request getOrganiztionsByPageRequest = new BaselineGetOrganiztionsByPage2Request();
                    getOrganiztionsByPageRequest.setOrganizationName(searchValue);
                    getOrganiztionsByPageRequest.setStart(0);
                    getOrganiztionsByPageRequest.setLimit(1000);
                    Result<List<OrganizationSDO>> organiztionResult = baseDataService.baselineGetOrganiztionsByPage2(getOrganiztionsByPageRequest);
                    if(organiztionResult != null && CollectionUtils.isNotEmpty(organiztionResult.getResult())){
                        List<String> organizationIdList = organiztionResult.getResult().stream().map(x->x.getId()).collect(Collectors.toList());
                        getEmployeesByRoleRequest.setRelationOrganizationIds(organizationIdList);
                    }else{
                        return false;
                    }
                    break;
                default: {
                    throw new FacadeException(ErrorMessage.code("OTS-01-001-02-15-005"));
                }
            }
        }
        return true;
    }

    private void enichRoleSDO(List<RoleSDO> list){
        if(list == null || CollectionUtils.isEmpty(list)){
            return;
        }
        //补充名称
        List<String> creatorIdList = list.stream().map(x->x.getCreatorId()).collect(Collectors.toList());
        List<String> modifierIdList = list.stream().map(x->x.getModifierId()).collect(Collectors.toList());
        creatorIdList.addAll(modifierIdList);
        BaselineGetEmployeeByIdsAllRequest getEmployeeRequest = BaselineGetEmployeeByIdsAllRequest.builder()
                .ids(creatorIdList.stream().distinct().collect(Collectors.toList())).build();
        Result<List<EmployeeSDO>> employeeResult = baseDataService.baselineGetEmployeeByIdsAll(getEmployeeRequest);
        Map<String,EmployeeSDO> employeeMap = Nullable.stream(employeeResult.getResult()).collect(Collectors.toMap(EmployeeSDO::getId, Function.identity(),(v1, v2)->v1));

        list.stream().forEach(x->{
            EmployeeSDO creator = employeeMap.get(x.getCreatorId());
            if(creator != null){
                x.setCreatorName(creator.getName());
            }
            EmployeeSDO modifier = employeeMap.get(x.getModifierId());
            if(modifier != null){
                x.setModifierName(modifier.getName());
            }
        });
    }

    /**
     * 展示所有权限
     *
     * @param menuGroupList 菜单分组集合
     * @return 权限树集合
     */
    public List<PermissionGroupTree> listPermission(List<String> menuGroupList,Map<String,PermissionSDO> rolePermissionMap) {
        List<PermissionGroupTree> roleRespList = new ArrayList<>();
        for (String menuGroup : menuGroupList) {
            PermissionTreePortalResp superRoot = listPermissionTreeResponse(menuGroup,rolePermissionMap);
            PermissionGroupTree permissionGroupResp = new PermissionGroupTree();
            permissionGroupResp.setMenuGroup(menuGroup);
            permissionGroupResp.setPermissionTreeList(superRoot.getChildren()!=null?superRoot.getChildren():new ArrayList());
            roleRespList.add(permissionGroupResp);
        }
        return roleRespList;
    }

    /**
     * 转换为树
     *
     * @param menuGroup 菜单分组参数
     * @return 菜单树
     */
    private PermissionTreePortalResp listPermissionTreeResponse(String menuGroup, Map<String,PermissionSDO> rolePermissionMap) {
        BaselineGetGroupMenusRequest getGroupMenusRequest = new BaselineGetGroupMenusRequest();
        getGroupMenusRequest.setMenuGroup(menuGroup);
        Result<List<MenuSDO>> menuResult = baseDataService.baselineGetGroupMenus(getGroupMenusRequest);
        if(menuResult == null || CollectionUtils.isEmpty(menuResult.getResult())){
            return new PermissionTreePortalResp();
        }
        List<MenuSDO> menus = menuResult.getResult();
        Map<String, String> menuIdToPermissionIdMap = menus.stream().collect(Collectors.toMap(MenuSDO::getId, MenuSDO::getPermissionId, (a, b) -> a));
        // 将菜单的ID转为权限的ID
        for (MenuSDO menuSDO : menuResult.getResult()) {
            //把每条数据的permissionId变为菜单id
            menuSDO.setId(menuIdToPermissionIdMap.get(menuSDO.getId()));
            // 同理，对应的父id也需要换掉，不然对应不上，不是最顶级，则需要替换
            if (!Objects.equals(menuSDO.getParentId(),PORTAL_MENU_ROOT_PARENT_ID)) {
                menuSDO.setParentId(menuIdToPermissionIdMap.get(menuSDO.getParentId()));
            }
        }
        Map<String, PermissionTreePortalResp> permissionMap = menus.stream().collect(Collectors.toMap(MenuSDO::getId, item -> {
            PermissionTreePortalResp permissionTreePortalResp = new PermissionTreePortalResp();
            BeanUtils.copyProperties(item,permissionTreePortalResp);
            return permissionTreePortalResp;
        }, (a, b) -> a));

        // convert to vo tree
        List<PermissionTreePortalResp> permissionTreeResponList = new ArrayList<>();
        for (Map.Entry<String, PermissionTreePortalResp> entry : permissionMap.entrySet()) {
            PermissionTreePortalResp permissionTreePortalResp = entry.getValue();
            if (rolePermissionMap.get(permissionTreePortalResp.getId()) != null){
                permissionTreePortalResp.setHaving(true);
            }
            String parentId = permissionTreePortalResp.getParentId();
            PermissionTreePortalResp permissionTreePortalRespParent = permissionMap.get(parentId);
            if (permissionTreePortalRespParent != null) {
                List<PermissionTreePortalResp> childrenList = permissionTreePortalRespParent.getChildren();
                if(CollectionUtils.isEmpty(childrenList)){
                    permissionTreePortalRespParent.setChildren(Lists.newArrayList(permissionTreePortalResp));
                }else{
                    childrenList.add(permissionTreePortalResp);
                }
            }
            if (Objects.equals(permissionTreePortalResp.getParentId(), PORTAL_MENU_ROOT_PARENT_ID)) {
                permissionTreeResponList.add(permissionTreePortalResp);
            }
        }
        // 排序
        PermissionTreePortalResp superRoot = new PermissionTreePortalResp();
        superRoot.setChildren(permissionTreeResponList);
        superRoot.sort();
        return superRoot;
    }

}
